package controller

import (
	"time"

	. "gddgame.cc/galaxy/common/dsl/web"
	"gddgame.cc/galaxy/core/models"
	"gddgame.cc/galaxy/utils/serialize/msgpack"

	"gddgame.cc/galaxy/utils/def"

	"github.com/dgrijalva/jwt-go"
)

type AppClaim struct {
	Policy []byte
	OpenId string
	jwt.StandardClaims
}

var (
	s def.Serialize
)

func init() {
	s = msgpack.Msgpack(true)
}

// 生成授权令牌: app客户端访问平台外部服务
// policy: key=> orbit.sync:type   value=>block
//               服务   模块  键            值
func GenerateAccessToken(context def.Context, app *models.App, openId string, policy map[string]interface{}, expire int) (string, error) {
	var err error

	b, err := s.Marshal(policy)
	if err != nil {
		return "", SystemExceptionDetail("Sign Fail", err)
	}
	claims := &AppClaim{
		b,
		openId,
		jwt.StandardClaims{
			ExpiresAt: time.Now().Unix() + int64(expire),
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	ss, err := token.SignedString([]byte(app.JwtSecret))
	if err != nil {
		context.Error(err)
		return "", SystemExceptionDetail("Sign Generate Fail", err)
	}
	return ss, err
}

// 解析授权令牌: app客户端访问平台外部服务
func ParseAccessToken(context def.Context, appAppId string, appToken string, token string) (*models.App, string, map[string]interface{}, error) {
	var err error
	app, err := ValidToken(context, appAppId, appToken)
	if err != nil {
		return nil, "", nil, err
	}
	t, err := jwt.ParseWithClaims(token, &AppClaim{}, func(t *jwt.Token) (interface{}, error) {
		return []byte(app.JwtSecret), nil
	})
	if err != nil || !t.Valid {
		return nil, "", nil, SystemExceptionDetail("Sign Valid Fail", err)
	}
	if claims, ok := t.Claims.(*AppClaim); ok {
		var data map[string]interface{}
		if err := s.Unmarshal(claims.Policy, &data); err != nil {
			return nil, "", nil, SystemExceptionDetail("Sign Policy error", err)
		}
		return app, claims.OpenId, data, nil
	} else {
		return nil, "", nil, SystemExceptionDetail("Sign Data error", err)
	}
}
